// 发送HTTP请求

import parseResponse from "./httpResponse";

const net = require("net");

interface HttpMessage {
  method: string;
  host: string;
  path: string;
  port: string;
  header?: {
    [propName: string]: any;
  };
  body?: {
    [propName: string]: any;
  };
  bodyText?: string;
}

interface ResponseMessage {
  header: {
    statusLine: string;
    headerSegment: {
      [propName: string]: any;
    };
  };
  body: string;
}

// 将http报文发送给端，并接收响应
export default class HttpRequest {
  httpMessage: HttpMessage = {
    method: "GET",
    host: "",
    path: "",
    port: "",
  };

  responseMessage: ResponseMessage = {
    header: {
      statusLine: "rwetw",
      headerSegment: {},
    },
    body: "",
  };

  constructor(option: HttpMessage) {
    this.httpMessage.method = option.method;
    this.httpMessage.host = option.host;
    this.httpMessage.path = option.path;
    this.httpMessage.port = option.port;
    this.httpMessage.header = option.header || {};
    this.httpMessage.body = option.body || {};

    if (!this.httpMessage.header["Content-Type"]) {
      this.httpMessage.header["Content-Type"] = "application/x-www-from-urlencoded";
    }

    if (this.httpMessage.header["Content-Type"] === "application/x-www-from-urlencoded") {
      this.httpMessage.bodyText = Object.keys(this.httpMessage.body)
        .map((key) => `${key}=${encodeURIComponent(this.httpMessage.body[key])}`)
        .join("&");
    } else if (this.httpMessage.header["Content-Type"] === "application/json") {
      this.httpMessage.bodyText = JSON.stringify(this.httpMessage.body);
    }

    this.httpMessage.header["Content-Length"] = this.httpMessage.bodyText.length;
  }

  // 将httpMessage对象字符串化并返回
  toString() {
    return `${this.httpMessage.method} ${this.httpMessage.path} HTTP/1.1\r\n${Object.keys(
      this.httpMessage.header
    )
      .map((key) => `${key}: ${this.httpMessage.header[key]}`)
      .join("\r\n")}\r\n\r\n${this.httpMessage.bodyText}`;
  }

  // 和服务端建立TCP连接，并发送Htpp请求
  async send() {
    await new Promise((resolve, reject) => {
      const connection = net.createConnection(
        {
          host: this.httpMessage.host,
          port: this.httpMessage.port,
        },
        () => {
          // 发送http请求
          connection.write(this.toString());
        }
      );
      connection.on("data", (data: any) => {
        // 保存响应的数据
        resolve(parseResponse(data.toString()));
        connection.end();
      });

      connection.on("err", (err: any) => {
        reject(err);
        connection.end();
      });
    })
      .then((reponse: any) => {
        this.responseMessage = reponse;
      })
      .catch((err) => {
        throw new Error(err);
      });
  }
}
